/*
 * This file is part of quickReminder, a software for gamers
 *
 * Copyright (C) 2006-2008 Lucas Romero
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace UserNotifier
{
    public class GammaWarnModule : WarnModule
    {
        static private UInt16[] _RampSaved = new UInt16[256 * 3];
        private int m_Duration = 300;

        public int Duration
        {
            get { return m_Duration; }
            set { m_Duration = value; }
        }

        private int m_WarnGammaValue = 120;

        public int Brightness
        {
            get { return m_WarnGammaValue; }
            set {
                if (value < 1 || value > 256)
                    throw new ArgumentOutOfRangeException("Brightness");
                m_WarnGammaValue = value;
            }
        }

        public override string Description
        {
            get
            {
                return Info.GammaDesc;
            }
        }

        public GammaWarnModule(int interval, int duration)
            : base(interval)
        {
            m_Duration = duration;
        }

        public GammaWarnModule()
            : base(5000)
        {
            
        }

        public override WarnModuleTypes Type
        {
            get { return WarnModuleTypes.GammaWarnModule; }
        }

        protected override void Warn()
        {
            RAMP r = new RAMP();
            GetGamma(ref r);
            SetGamma(m_WarnGammaValue);
            System.Threading.Thread.Sleep(m_Duration);

            IntPtr hdc = LucasCode.Win32.User32.GetDC(IntPtr.Zero);
            SetDeviceGammaRamp(hdc, ref r);
            LucasCode.Win32.User32.ReleaseDC(IntPtr.Zero, hdc);
        }

        public static void NullGamma()
        {
            SetGamma(50);
        }


        [DllImport("gdi32.dll", EntryPoint = "GetDeviceGammaRamp")]
        static private extern bool GetDeviceGamma(IntPtr hdc, UInt16[] lpRamp);

        [DllImport("gdi32.dll", EntryPoint = "SetDeviceGammaRamp")]
        static private extern bool SetDeviceGamma(IntPtr hdc, UInt16[] lpRamp);

        [DllImport("gdi32.dll")]
        public static extern int GetDeviceGammaRamp(IntPtr hDC, ref RAMP lpRamp);

        [DllImport("gdi32.dll")]
        public static extern int SetDeviceGammaRamp(IntPtr hDC, ref RAMP lpRamp);


        public struct RAMP
        {
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public UInt16[] Red;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public UInt16[] Green;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public UInt16[] Blue;

        }

        public static void SetGamma(int gamma)

        {
          if (gamma <= 256 && gamma >= 1)
          {
           RAMP ramp = new RAMP();
           ramp.Red = new ushort[256];
           ramp.Green = new ushort[256];
           ramp.Blue = new ushort[256];
           for( int i=1; i<256; i++ )
           {
            int iArrayValue = i * (gamma + 128);

            if (iArrayValue > 65535)
            iArrayValue = 65535;
            ramp.Red[i] = ramp.Blue[i] = ramp.Green[i] = (ushort)iArrayValue;
           }
           IntPtr hdc = LucasCode.Win32.User32.GetDC(IntPtr.Zero);
           SetDeviceGammaRamp(hdc, ref ramp);
           LucasCode.Win32.User32.ReleaseDC(IntPtr.Zero, hdc);
          }
        }

        public static int GetGamma(ref RAMP ramp)
        {
            IntPtr hdc = LucasCode.Win32.User32.GetDC(IntPtr.Zero);
            int res = GetDeviceGammaRamp(hdc, ref ramp);
            LucasCode.Win32.User32.ReleaseDC(IntPtr.Zero, hdc);
            return res;
        }

        /*static public float GetGamma()
        {
            IntPtr hdc = LucasCode.Win32.User32.GetDC(IntPtr.Zero);

            GetDeviceGamma(hdc, _RampSaved);

            LucasCode.Win32.User32.ReleaseDC(IntPtr.Zero, hdc);

            float[] rgb = { 1.0f, 1.0f, 1.0f };

            for (int i = 0; i < 3; i++)
            {
                float Csum = 0.0f;
                int Ccount = 0;
                int min = 256 * i;
                int max = min + 256;

                for (int j = min; j < max; j++)
                {

                    if (j != 0 && _RampSaved[j] != 0)
                    {
                        double B = (j % 256) / 256.0;
                        double A = _RampSaved[j] / 65536.0;
                        float C = (float)(Math.Log(A) / Math.Log(B));

                        Csum += C;
                        Ccount++;
                    }
                }

                rgb[i] = Csum / Ccount;
            }

            return rgb[0];
        }*/

        static public bool SetGamma(float Gamma)
        {
            UInt16[] ramp = new UInt16[256 * 3];

            for (int i = 0; i < 256; i++)
            {
                ramp[i] = ramp[i + 256] = ramp[i + 512] =
                (UInt16)Math.Min(65535, Math.Max(0, Math.Pow((float)((i + 1) / 256.0), (float)Gamma) * 65535 + 0.5));
            }

            IntPtr hdc = LucasCode.Win32.User32.GetDC(IntPtr.Zero);

            SetDeviceGamma(hdc, ramp);

            LucasCode.Win32.User32.ReleaseDC(IntPtr.Zero, hdc);

            return true;
        }
    }
}
